package by.bucha.testproject.imageLoader;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.channels.FileChannel;
import java.util.ArrayList;
import java.util.List;

import android.os.Environment;
import android.os.StatFs;

public class ExternalFileCache {

	private static ExternalFileCache sInstance;

	private ExternalFileCache() {
		File file = new File(mDirrectoryName);
		file.mkdir();
	}

	public static ExternalFileCache getInstance() {
		if (sInstance == null) {
			sInstance = new ExternalFileCache();
		}
		return sInstance;
	}

	private String mDirrectoryName = Environment.getExternalStorageDirectory()
			+ "/testProject/";

	/* Checks if external storage is available for read and write */
	private boolean isExternalStorageWritable() {
		String state = Environment.getExternalStorageState();
		if (Environment.MEDIA_MOUNTED.equals(state)) {
			return true;
		}
		return false;
	}

	public int getCount() {
		File filePuth = new File(mDirrectoryName);

		File[] files = filePuth.listFiles();
		int count = 0;
		for (@SuppressWarnings("unused")
		File file : files) {
			++count;
		}
		return count;
	}

	public List<String> getFilePathes() {
		File filePuth = new File(mDirrectoryName);

		File[] files = filePuth.listFiles();
		List<String> list = new ArrayList<String>();
		for (File file : files) {
			list.add(file.getAbsolutePath());
		}
		return list;
	}

	/* Checks if external storage is available to at least read */
	private boolean isExternalStorageReadable() {
		String state = Environment.getExternalStorageState();
		if (Environment.MEDIA_MOUNTED.equals(state)
				|| Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
			return true;
		}
		return false;
	}

	private NullPointerException nullKeyException() {
		return new NullPointerException(
				"In LRU cache key must'n be null or empty.");
	}

	private IllegalAccessException writeException() {
		return new IllegalAccessException(
				"Cant write to external storage,check permissons!");
	}

	private IllegalAccessException readException() {
		return new IllegalAccessException(
				"Cant read from external storage, check permissons!");
	}

	private IOException deleteException() {
		return new IOException("Cant delete file from folder!");
	}

	private IOException noMemoryException() {
		return new IOException("No memory to coppy file!");
	}

	/**
	 * @return Number of bytes available on external storage
	 */
	private static long getExternalStorageAvailableSpace() {
		long availableSpace = -1;
		StatFs stat = new StatFs(Environment.getExternalStorageDirectory()
				.getPath());
		stat.restat(Environment.getExternalStorageDirectory().getPath());
		availableSpace = (long) stat.getAvailableBlocks()
				* (long) stat.getBlockSize();

		return availableSpace;
	}

	private Boolean isHaveFreeSpace(String filePath) {
		File fileToDownload = new File(filePath);
		long needSpace = fileToDownload.length();
		long freeSpace = getExternalStorageAvailableSpace();
		if (freeSpace >= needSpace) {
			return true;
		} else {
			return false;
		}
	}

	private void copyFile(String filePuth) throws IOException {
		File src = new File(filePuth);
		File dst = new File(mDirrectoryName + src.getName());
		FileChannel inChannel = null;
		FileChannel outChannel = null;
		try {
			inChannel = new FileInputStream(src).getChannel();
			outChannel = new FileOutputStream(dst).getChannel();
			inChannel.transferTo(0, inChannel.size(), outChannel);
		} finally {
			if (inChannel != null) {
				try {
					inChannel.close();
				} catch (IOException e) {
					throw e;
				}
			}
			if (outChannel != null) {
				try {
					outChannel.close();
				} catch (IOException e) {
					throw e;
				}
			}
		}
	}

	/*
	 * private void removeEldest() throws Exception { File filePuth = new
	 * File(mDirrectoryName);
	 * 
	 * File[] files = filePuth.listFiles(); Date lastModifiedDate = null; File
	 * fileToDelete = null; for (File file : files) { Date date = new
	 * Date(file.lastModified()); if (lastModifiedDate == null ||
	 * date.before(lastModifiedDate)) { lastModifiedDate = date; fileToDelete =
	 * file; } } if (fileToDelete != null) {
	 * 
	 * Boolean isDeleted = fileToDelete.delete(); if (isDeleted == false) {
	 * throw deleteException(); } } else { throw noMemoryException(); } }
	 */

	public void put(String filePuth) throws Exception {
		if (filePuth == null || filePuth.equals("")) {
			throw nullKeyException();
		}
		if (!isExternalStorageWritable()) {
			throw writeException();
		}
		if (!isHaveFreeSpace(filePuth)) {
			throw noMemoryException();
		}
		copyFile(filePuth);
	}

	public void remove(String filePuth) throws IOException,
			IllegalAccessException {
		if (filePuth == null || filePuth.equals("")) {
			throw nullKeyException();
		}
		if (!isExternalStorageReadable()) {
			throw readException();
		}

		File fileToDelete = new File(filePuth);
		if (fileToDelete != null) {
			Boolean isDeleted = fileToDelete.delete();
			if (isDeleted == false) {
				throw deleteException();
			}
		}
	}

}
